﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Net.Sockets;
using IPMsgExpections;
using CommonUtility;
using Microsoft.Phone.Info;

namespace IPMSG
{
    /// <summary>
    /// 获取配置信息，本机信息（如用户名、主机名）并启动TCP监听
    /// </summary>
    internal class MyInfo
    {
        private static readonly MyInfo instance = new MyInfo();

        //本机IP
        private IPAddress localipAddress;

        //包序号
        private uint indexPackage;

        //用户名
        private string userName;

        //主机名
        private string hostName;

        //消息是否带CheckOPT（对方收到后需要回复确认消息）
        private bool checkOPT;

        //消息是封装
        private bool secretOPT;

        //单件模式
        internal static MyInfo Instance
        {
            get { return MyInfo.instance; }
        }

        //获取本机IP
        public IPAddress LocalipAddress
        {
            get { return this.localipAddress; }
        }

        //获取包序号，每次获取包序号自增1
        internal uint IndexPackage
        {
            get
            {
                this.indexPackage++;
                return indexPackage - 1;
            }
        }

        //或者或设置用户名
        public string UserName
        {
            get { return userName; }
            set { userName = value; }
        }

        //获取或设置主机名
        public string HostName
        {
            get { return hostName; }
            set { hostName = value; }
        }

        //获取或者设置发送消息是否带CheckOPT（对方收到后需要回复确认消息）
        public bool CheckOPT
        {
            get { return checkOPT; }
            set { checkOPT = value; }
        }

        //获取或者设置发送消息是否封装
        public bool SecretOPT
        {
            get { return this.secretOPT; }
            set { this.secretOPT = value; }
        }

        //私有构造函数
        private MyInfo()
        {
        }

        /// <summary>
        /// 启动TCP Adapter server
        /// </summary>
        internal void Start()
        {
            Log.Info("Reading information of this computer...");

            try
            {
                string anid = UserExtendedProperties.GetValue("ANID") as string;
                this.userName = (anid == string.Empty || anid == null) ? "NOT VALID" : anid;
                this.hostName = Microsoft.Phone.Info.DeviceStatus.DeviceName;
                this.indexPackage = 1;

                //需要从配置文件读出
                //暂时默认值
                this.checkOPT = true;
                this.secretOPT = true;
            }
            catch (Exception ex)
            {
                throw new NetExpection(ex.Message, ex);
            }

            try
            {
                //尝试通过接收自己发出的广播数据获取本机IP
                //using (MyIPAddress myipAddress = new MyIPAddress())
                //{
                //    myipAddress.TryGetLocalIP(addressRet =>
                //        {
                //            this.localipAddress = addressRet;
                //        });
                //}

                //Log.Info(string.Format("获得本地IP地址为:{0}", this.localipAddress.ToString()));
            }
            catch (Exception ex)
            {
                throw new NetExpection(ex.Message, ex);
            }
        }
    }

    internal class MyIPAddress : IDisposable
    {
        //回调委托
        private Action<IPAddress> foundCallback;

        //多播UDP
        private UdpAnySourceMulticastClient udpListener;

        //发出的随机广播数据
        private byte[] bytesSend = new byte[40];

        //收到的数据
        private byte[] byteBuff;

        //随机广播端口(10000-65535)
        private int randomPort;

        public MyIPAddress()
        {
            Random randomSeed = new Random(System.Environment.TickCount);
            this.randomPort = randomSeed.Next(10000, 65536);
            randomSeed.NextBytes(this.bytesSend);
        }

        internal void TryGetLocalIP(Action<IPAddress> callback)
        {
            this.foundCallback = callback;

            //绑定到随机端口
            try
            {
                udpListener = new UdpAnySourceMulticastClient(IPAddress.Parse(ConstWords.IPMSG_BroadcastIP), this.randomPort);
            }
            catch (Exception ex)
            {
                throw new NetExpection(string.Format("获取本机IP时绑定UDP失败.{0}", ex.Message));
            }

            //开始加入广播组
            udpListener.BeginJoinGroup(
                result =>
                {
                    try
                    {
                        udpListener.EndJoinGroup(result);
                    }
                    catch (Exception ex)
                    {
                        throw new NetExpection("获取本机IP时加入局域网广播组失败.", ex);
                    }
                },
                null);

            this.byteBuff = new byte[ConstWords.IPMSG_UDPMaxMessage];

            //开始异步接收UDP消息
            udpListener.BeginReceiveFromGroup(
                this.byteBuff,
                0,
                ConstWords.IPMSG_UDPMaxMessage,
                new AsyncCallback(this.MessageAccepter),
                null);

            //向制定的随机端口广播
            try
            {
                udpListener.BeginSendToGroup(
                    this.bytesSend,
                    0,
                    this.bytesSend.Length,
                    result =>
                    {
                        udpListener.EndSendToGroup(result);
                    },
                    null);
            }
            catch (Exception ex)
            {
                throw new NetExpection("向局域网广播消息失败.", ex);
            }
        }

        //异步接收UDP数据
        private void MessageAccepter(IAsyncResult result)
        {
            IPEndPoint remoteIEP = null;

            byte[] bytesReceive = null;

            int bytesRcvLength;

            try
            {
                //接收消息
                bytesRcvLength = udpListener.EndReceiveFromGroup(result, out remoteIEP);
                bytesReceive = new byte[bytesRcvLength];
                Array.Copy(this.byteBuff, bytesReceive, bytesRcvLength);
                if (System.Linq.Enumerable.SequenceEqual<byte>(bytesReceive, this.bytesSend))
                {
                    this.foundCallback(remoteIEP.Address);
                }
                else
                {
                    Array.Clear(this.byteBuff, 0, this.byteBuff.Length);
                    udpListener.BeginReceiveFromGroup(
                        this.byteBuff,
                        0,
                        ConstWords.IPMSG_UDPMaxMessage,
                        new AsyncCallback(this.MessageAccepter),
                        null);
                }
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("获取本机IP时加入接收广播消息失败.{0}", ex.Message));
            }
        }

        public void Dispose()
        {
            this.udpListener.Dispose();
        }
    }
}
